package com.liaoyifan.core.thread;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;

@Log4j2
public class CorePool {
    @Getter private final CoreExecutor executor;
    private final ScheduledExecutorService monitorExecutor;
    private final ScheduledFuture<?> monitorFuture;
    private final AtomicBoolean shuttingDown = new AtomicBoolean(false);

    public CorePool(
            CoreExecutor executor,
            ScheduledExecutorService monitorExecutor,
            ScheduledFuture<?> monitorFuture) {
        this.executor = executor;
        this.monitorExecutor = monitorExecutor;
        this.monitorFuture = monitorFuture;
    }

    public void shutdown() {
        if (!shuttingDown.compareAndSet(false, true)) {
            return; // 已在关闭中，直接返回
        }
        try {
            log.info(() -> "Start shutdown executor: " + executor.getConfig().getPoolName());
            // 1. 关闭主线程池
            executor.shutdown();
            try {
                if (!executor.awaitTermination(10, TimeUnit.MINUTES)) {
                    log.warn(
                            "Forcing shutdown of executor: {}", executor.getConfig().getPoolName());
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt(); // 恢复中断状态
                log.error("Shutdown interrupted for executor", e);
            }

            // 2. 关闭监控线程池
            monitorExecutor.shutdown();
            try {
                if (!monitorExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
                    log.warn("Forcing shutdown of monitor: {}", executor.getConfig().getPoolName());
                    monitorExecutor.shutdownNow();
                }
            } catch (InterruptedException e) {
                monitorExecutor.shutdownNow();
                Thread.currentThread().interrupt(); // 恢复中断状态
                log.error("Shutdown interrupted for monitor", e);
            }
        } finally {
            // 3. 停止监控任务
            monitorFuture.cancel(true);
        }
    }

    public static CorePool create(PoolConfig config) {
        // 创建主线程池
        ThreadPoolExecutor executor =
                new ThreadPoolExecutor(
                        config.getCorePoolSize(),
                        config.getMaximumPoolSize(),
                        config.getKeepAliveTime(),
                        config.getUnit(),
                        config.getWorkQueue(),
                        ThreadFactoryBuilder.builder()
                                .nameFormat(config.getPoolName() + "-%d")
                                .daemon(false)
                                .build(),
                        config.getHandler());
        executor.allowCoreThreadTimeOut(true);
        // 创建监控线程池
        ScheduledExecutorService monitorExecutor =
                Executors.newSingleThreadScheduledExecutor(
                        ThreadFactoryBuilder.builder()
                                .nameFormat(config.getPoolName() + "-monitor")
                                .daemon(true)
                                .build());
        // 启动监控任务
        ScheduledFuture<?> monitorFuture =
                monitorExecutor.scheduleAtFixedRate(
                        () ->
                                log.info(
                                        "{}: Max={}, Active={}, Queue={}, Completed={}, Total={}",
                                        config.getPoolName(),
                                        executor.getMaximumPoolSize(),
                                        executor.getActiveCount(),
                                        executor.getQueue().size(),
                                        executor.getCompletedTaskCount(),
                                        executor.getTaskCount()),
                        0,
                        config.getMonitorPeriod(),
                        TimeUnit.SECONDS);
        return new CorePool(new CoreExecutor(config, executor), monitorExecutor, monitorFuture);
    }
}
